﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using ParserGenerator.CharacterMapping;

namespace ParserGenerator.ScannerConstruction
{
    [Serializable]
    public sealed class ScannerAutomatonTransitions : ReadOnlyDictionary<CharClass, ScannerAutomatonTransition>
    {
        public ScannerAutomatonState State { get; }

        internal ScannerAutomatonTransitions(ScannerAutomatonState state)
            : base(new Dictionary<CharClass, ScannerAutomatonTransition>())
        {
            if (state == null)
                throw new ArgumentNullException(nameof(state));
            State = state;
        }

        internal void Add(CharClass symbol, ScannerAutomatonState target)
        {
            if (symbol == null)
                throw new ArgumentNullException(nameof(symbol));
            if (target == null)
                throw new ArgumentNullException(nameof(target));
            ScannerAutomatonTransition tran = new ScannerAutomatonTransition(State, symbol, target);
            Dictionary.Add(symbol, tran);
        }

        internal void Update(CharClass symbol, ScannerAutomatonState target)
        {
            if (symbol == null)
                throw new ArgumentNullException(nameof(symbol));
            if (target == null)
                throw new ArgumentNullException(nameof(target));
            ScannerAutomatonTransition tran = new ScannerAutomatonTransition(State, symbol, target);
            Dictionary[symbol] = tran;
        }

        internal void Clear()
        {
            Dictionary.Clear();
        }

        public ScannerAutomatonTransition GetTransition(CharClass symbol)
        {
            if (symbol == null)
                throw new ArgumentNullException(nameof(symbol));
            ScannerAutomatonTransition tran;
            if (!Dictionary.TryGetValue(symbol, out tran))
            {
                string message = string.Format(SR.NoTransitionDefinedForStateAndSymbol, State, symbol);
                InvalidOperationException e = new InvalidOperationException(message);
                throw e;
            }
            return tran;
        }

        public ScannerAutomatonTransition TryGetTransition(CharClass symbol)
        {
            if (symbol == null)
                throw new ArgumentNullException(nameof(symbol));
            ScannerAutomatonTransition tran;
            Dictionary.TryGetValue(symbol, out tran);
            return tran;
        }

        public new ScannerAutomatonState this[CharClass symbol]
        {
            get
            {
                if (symbol == null)
                    throw new ArgumentNullException(nameof(symbol));
                ScannerAutomatonTransition tran = GetTransition(symbol);
                return tran.Target;
            }
        }
    }
}
